import { io, Socket } from 'socket.io-client';

// RTCConfiguration 类型定义
interface RTCIceServer {
  urls: string | string[];
  username?: string;
  credential?: string;
}

// WebRTC配置
const rtcConfig: RTCConfiguration = {
  iceServers: [
    { urls: 'stun:stun.l.google.com:19302' },
    { urls: 'stun:stun1.l.google.com:19302' },
    { urls: 'stun:stun2.l.google.com:19302' }
  ]
};

// 定义事件处理函数的类型
type EventCallback = (...args: any[]) => void;

// 定义事件映射类型
interface EventMap {
  [event: string]: EventCallback[];
}

class WebRTCService {
  socket: Socket | null;
  localStream: MediaStream | null;
  peerConnections: Record<string, RTCPeerConnection>;
  roomId: string | null;
  userId: string | null;
  events: EventMap;
  isConnected: boolean;

  constructor() {
    // socket ID
    this.socket = null;
    // 本地流
    this.localStream = null;
    // 存储与其他用户的连接
    this.peerConnections = {};
    // 房间ID
    this.roomId = null;
    // 用户ID
    this.userId = null;
    // 事件监听器
    this.events = {};
    // 连接状态
    this.isConnected = false;
  }

  // 初始化socket连接
  connect(): void {
    // 防止重复连接
    if (this.socket && this.isConnected) {
      return;
    }
    // 连接服务器
    this.socket = io('http://localhost:5000');
    // 监听连接事件
    this.socket.on('connect', () => {
      console.log('已连接到信令服务器');
      this.isConnected = true;
      this.emit('connection-established');
    });
    // 监听连接断开事件
    this.socket.on('disconnect', () => {
      console.log('与信令服务器断开连接');
      this.isConnected = false;
      this.emit('connection-lost');
    });

    // 监听其他用户连接
    this.socket.on('user-connected', (userId: string) => {
      console.log('新用户已连接:', userId);
      
      // 确保不处理自己的连接事件
      if (userId !== this.userId) {
        this.emit('user-connected', userId);
        
        // 如果我们已经有本地流，则创建与新用户的对等连接
        if (this.localStream) {
          this.createPeerConnection(userId);
        }
      }
    });

    // 监听其他用户断开连接
    this.socket.on('user-disconnected', (userId: string) => {
      console.log('用户已断开连接:', userId);
      
      // 确保不处理自己的断开连接事件
      if (userId !== this.userId) {
        this.emit('user-disconnected', userId);
        this.closePeerConnection(userId);
      }
    });

    // 监听获取房间现有用户信息事件
    this.socket.on('existing-users', (userIds: string[]) => {
      console.log('房间内现有的用户:', userIds);
      
      // 过滤掉自己的ID
      const filteredUserIds = userIds.filter(id => id !== this.userId);
      console.log('过滤后的现有用户:', filteredUserIds);
      
      this.emit('existing-users', filteredUserIds);
      
      // 为每个现有用户创建对等连接
      if (this.localStream) {
        filteredUserIds.forEach(userId => {
          setTimeout(() => {
            this.createPeerConnection(userId);
          }, 1000); // 延迟1秒创建连接，确保信令服务器已经处理用户加入事件
        });
      }
    });

    // 监听offer事件
    this.socket.on('offer', async (offer: RTCSessionDescriptionInit, fromUserId: string, toUserId?: string) => {
      console.log('收到offer:', fromUserId, '目标用户:', toUserId || '全部');
      try {
        // 只处理发送给当前用户的offer
        if (toUserId && toUserId !== this.userId) {
          return;
        }
        
        // 避免处理自己的offer
        if (fromUserId === this.userId) {
          return;
        }
        
        // 确保连接存在，如果不存在则创建
        if (!this.peerConnections[fromUserId]) {
          console.log(`为用户 ${fromUserId} 创建新的对等连接（响应offer）`);
          await this.createPeerConnection(fromUserId, false); // 不自动发送offer
        }
        
        const pc = this.peerConnections[fromUserId];
        // 检查是否已经设置了远程描述
        const signalingState = pc.signalingState;
        if (signalingState !== 'stable') {
          console.log(`当前信令状态: ${signalingState}，重置连接`);
          await this.resetPeerConnection(fromUserId);
          return; // 重置后会重新收到offer
        }
        
        console.log(`为用户 ${fromUserId} 设置远程描述（offer）`);
        await pc.setRemoteDescription(new RTCSessionDescription(offer));
        
        console.log(`为用户 ${fromUserId} 创建answer`);
        const answer = await pc.createAnswer();
        await pc.setLocalDescription(answer);
        
        console.log(`向用户 ${fromUserId} 发送answer`);
        this.socket?.emit('answer', answer, this.roomId, this.userId, fromUserId);
      } catch (error) {
        console.error('处理offer时出错:', error);
        // 尝试重置连接
        this.resetPeerConnection(fromUserId);
      }
    });

    // 监听answer事件
    this.socket.on('answer', async (answer: RTCSessionDescriptionInit, fromUserId: string, toUserId?: string) => {
      console.log('收到answer:', fromUserId, '目标用户:', toUserId || '全部');
      try {
        // 只处理发送给当前用户的answer
        if (toUserId && toUserId !== this.userId) {
          return;
        }
        
        // 避免处理自己的answer
        if (fromUserId === this.userId) {
          return;
        }
        // 判断链接是否存在
        if (this.peerConnections[fromUserId]) {
          const pc = this.peerConnections[fromUserId];
          console.log('pc', pc)
          // 检查信令状态
          if (pc.signalingState === 'have-local-offer') {
            console.log(`为用户 ${fromUserId} 设置远程描述（answer）`);
            await pc.setRemoteDescription(new RTCSessionDescription(answer));
          } else {
            console.log(`信令状态不正确: ${pc.signalingState}，无法设置远程描述`);
          }
        } else {
          console.log(`没有找到与用户 ${fromUserId} 的连接，无法处理answer`);
        }
      } catch (error) {
        console.error('处理answer时出错:', error);
      }
    });

    // 监听ICE事件
    this.socket.on('ice-candidate', async (candidate: RTCIceCandidateInit, fromUserId: string, toUserId?: string) => {
      console.log('收到ICE候选:', fromUserId, '目标用户:', toUserId || '全部');
      try {
        // 只处理发送给当前用户的ice候选
        if (toUserId && toUserId !== this.userId) {
          return;
        }
        
        // 避免处理自己的ice候选
        if (fromUserId === this.userId) {
          return;
        }
        
        if (this.peerConnections[fromUserId]) {
          const pc = this.peerConnections[fromUserId];
          
          // 只有在连接已初始化后才添加ICE候选
          if (pc.remoteDescription) {
            console.log(`为用户 ${fromUserId} 添加ICE候选`);
            await pc.addIceCandidate(new RTCIceCandidate(candidate));
          } else {
            console.log(`等待设置远程描述后再添加ICE候选`);
            // 可以将候选缓存起来，稍后添加
          }
        } else {
          console.log(`没有找到与用户 ${fromUserId} 的连接，无法处理ICE候选`);
        }
      } catch (error) {
        console.error('处理ICE候选时出错:', error);
      }
    });

    // 监听服务器信息和信令错误处理事件
    this.socket.on('server-info', (info: any) => {
      console.log('服务器信息:', info);
      this.emit('server-info', info);
    });

    // 监听信号错误
    this.socket.on('signal-error', (error: any) => {
      console.error('信令错误:', error);
      this.emit('signal-error', error);
      
      // 如果是user-not-found错误，可能需要重新请求用户列表
      if (error.error === 'user-not-found' && this.roomId) {
        console.log('用户未找到，请求更新用户列表');
        this.socket?.emit('request-users', this.roomId);
      }
    });
  }

  // 重置对等连接
  async resetPeerConnection(userId: string): Promise<void> {
    console.log(`重置与用户 ${userId} 的对等连接`);
    
    // 关闭现有连接
    this.closePeerConnection(userId);
    
    // 等待一段时间，确保关闭完成
    await new Promise(resolve => setTimeout(resolve, 1000));
    
    // 重新创建连接
    await this.createPeerConnection(userId);
  }

  // 加入房间
  joinRoom(roomId: string, userId: string): void {
    console.log(`加入房间: ${roomId}, 用户ID: ${userId}`);
    this.roomId = roomId;
    this.userId = userId;
    
    // 确保socket已连接
    if (this.socket && this.isConnected) {
      // 发送加入房间消息
      this.socket.emit('join-room', roomId, userId);
      
      // 请求房间内现有用户列表
      this.socket.emit('request-users', roomId);
    } else {
      console.error('无法加入房间: socket未连接');
      this.connect(); // 尝试连接
      // 连接成功后会触发connection-established事件，然后再加入房间
    }
  }

  // 离开房间
  leaveRoom(): void {
    console.log('离开房间');
    
    // 确保socket已连接
    if (this.socket && this.isConnected && this.roomId) {
      // 发送离开房间消息
      this.socket.emit('leave-room', this.roomId, this.userId);
    }
    
    // 关闭所有对等连接
    Object.keys(this.peerConnections).forEach(userId => {
      this.closePeerConnection(userId);
    });
    
    // 停止本地流
    if (this.localStream) {
      this.localStream.getTracks().forEach(track => {
        track.stop();
      });
      this.localStream = null;
    }
    
    // 重置状态
    this.roomId = null;
    this.userId = null;
  }

  // 创建与特定用户的WebRTC对等连接
  async createPeerConnection(userId: string, initiateOffer: boolean = true): Promise<RTCPeerConnection> {
    console.log(`创建与用户 ${userId} 的对等连接`);
    
    // 确保本地流存在
    if (!this.localStream) {
      console.log('本地流不存在，尝试获取媒体流');
      try {
        this.localStream = await this.getLocalStream();
      } catch (error) {
        console.error('获取本地媒体流失败:', error);
        throw new Error('无法创建对等连接: 本地媒体流不可用');
      }
    }
    
    // 如果已经存在连接，先关闭
    if (this.peerConnections[userId]) {
      console.log(`关闭已存在的与用户 ${userId} 的连接`);
      this.closePeerConnection(userId);
    }
    
    // 创建新的对等连接
    const pc = new RTCPeerConnection(rtcConfig);
    this.peerConnections[userId] = pc;
    
    // 添加本地流轨道到连接
    this.localStream.getTracks().forEach(track => {
      console.log(`添加轨道到对等连接: ${track.kind}`);
      pc.addTrack(track, this.localStream!);
    });
    
    // 处理ICE候选
    pc.onicecandidate = (event) => {
      if (event.candidate) {
        console.log(`为用户 ${userId} 生成ICE候选`);
        this.socket?.emit('ice-candidate', event.candidate, this.roomId, this.userId, userId);
      }
    };
    
    // 处理连接状态变化
    pc.onconnectionstatechange = () => {
      console.log(`与用户 ${userId} 的连接状态变化: ${pc.connectionState}`);
      
      if (pc.connectionState === 'disconnected' || pc.connectionState === 'failed') {
        console.log(`连接已断开或失败: ${userId}`);
        this.emit('peer-disconnected', userId);
      } else if (pc.connectionState === 'connected') {
        console.log(`连接已建立: ${userId}`);
        this.emit('peer-connected', userId);
      }
    };
    
    // 处理ICE连接状态变化
    pc.oniceconnectionstatechange = () => {
      console.log(`ICE连接状态变化: ${pc.iceConnectionState}`);
      
      if (pc.iceConnectionState === 'disconnected' || pc.iceConnectionState === 'failed') {
        console.log(`ICE连接已断开或失败: ${userId}`);
      }
    };
    
    // 处理接收到的轨道
    pc.ontrack = (event) => {
      console.log(`接收到用户 ${userId} 的轨道: ${event.track.kind}`);
      
      if (event.streams && event.streams[0]) {
        console.log(`将远程流与用户 ${userId} 关联`);
        this.emit('track-added', { userId, stream: event.streams[0] });
      }
    };
    
    // 如果需要主动发起连接，创建并发送offer
    if (initiateOffer) {
      try {
        console.log(`为用户 ${userId} 创建offer`);
        const offer = await pc.createOffer();
        
        console.log(`为用户 ${userId} 设置本地描述（offer）`);
        await pc.setLocalDescription(offer);
        
        console.log(`向用户 ${userId} 发送offer`);
        // 使用可选链运算符避免null错误
        this.socket?.emit('offer', pc.localDescription, this.roomId, this.userId, userId);
      } catch (error) {
        console.error('创建或发送offer时出错:', error);
        throw error;
      }
    }
    
    return pc;
  }

  // 关闭与特定用户的对等连接
  closePeerConnection(userId: string): void {
    console.log(`关闭与用户 ${userId} 的对等连接`);
    
    const pc = this.peerConnections[userId];
    if (pc) {
      // 关闭连接
      pc.onicecandidate = null;
      pc.ontrack = null;
      pc.onconnectionstatechange = null;
      pc.oniceconnectionstatechange = null;
      
      // 关闭所有数据通道
      const dataChannels = Object.values(pc);
      for (const dc of dataChannels) {
        if (dc && typeof dc === 'object' && 'close' in dc && typeof dc.close === 'function') {
          try {
            dc.close();
          } catch (error) {
            console.error('关闭数据通道时出错:', error);
          }
        }
      }
      
      // 关闭对等连接
      try {
        pc.close();
      } catch (error) {
        console.error('关闭对等连接时出错:', error);
      }
      
      // 从连接映射中删除
      delete this.peerConnections[userId];
    }
  }

  // 获取本地媒体流
  async getLocalStream(constraints: MediaStreamConstraints = { audio: true, video: true }): Promise<MediaStream> {
    console.log('请求本地媒体流, 约束:', constraints);
    
    if (!this.localStream) {
      console.log('获取新的媒体流');
      this.localStream = await navigator.mediaDevices.getUserMedia(constraints);
    }
    
    return this.localStream;
  }

  // 添加事件监听器
  on(event: string, callback: EventCallback): void {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    
    this.events[event].push(callback);
  }

  // 触发事件
  emit(event: string, ...args: any[]): void {
    const callbacks = this.events[event];
    if (callbacks) {
      callbacks.forEach(callback => {
        try {
          callback(...args);
        } catch (error) {
          console.error(`执行 ${event} 事件回调时出错:`, error);
        }
      });
    }
  }
}

// 创建并导出WebRTC服务单例
const webRTCService = new WebRTCService();
export default webRTCService; 